package ru.mirent.exceptions;

import org.opentest4j.AssertionFailedError;

import static java.util.Objects.isNull;

/**
 * <p>Реализация исключения с вложением и выводом в консоль блока сравнения: 'Click to see difference'.
 * <p>Обработка вложения производится в классе {@link ru.mirent.entity.listeners.allure.AllureTestLifecycleListener}.
 */
public class CustomAssertionFailedError extends AssertionFailedError {
    private final static String NEW_LINE = System.lineSeparator();
    private String message = null;
    private Object expected = null;
    private Object actual = null;
    private Object attachment = null;

    public CustomAssertionFailedError() {
        super();
    }

    public CustomAssertionFailedError(String message) {
        super(message);
        this.message = message;
    }

    public CustomAssertionFailedError(String message, Object expected, Object actual) {
        super(message, expected, actual);
        this.message = message;
        this.expected = expected;
        this.actual = actual;
    }

    public void setAttachment(Object attachment) {
        this.attachment = attachment;
    }

    public Object getAttachment() {
        return attachment;
    }

    public static Builder builder() {
        return new Builder();
    }

    /**
     * Метод переопределен, т.к. вызывается при логгировании сообщения об ошибке в консоль.
     * @return форматированное сообщение об ошибке
     */
    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();

        stringBuilder
                .append("Тип исключения: ")
                .append(this.getClass().getName());

        if (!super.getMessage().isEmpty()) {
            stringBuilder
                    .append(NEW_LINE)
                    .append("Сообщение ошибки: ")
                    .append(message);
        }

        if (!isNull(attachment)) {
            stringBuilder
                    .append(NEW_LINE)
                    .append("Вложение:")
                    .append(NEW_LINE)
                    .append(attachment);
        }

        return stringBuilder.toString();
    }

    public static class Builder {
        private String message = null;
        private Object expected = null;
        private Object actual = null;
        private Object attachment = null;

        private Builder() {
        }

        public Builder message(String value) {
            this.message = value;
            return this;
        }

        public Builder attachment(Object obj) {
            this.attachment = obj;
            return this;
        }

        public Builder expectedAndActual(Object expected, Object actual) {
            this.expected = expected;
            this.actual = actual;
            return this;
        }

        public CustomAssertionFailedError build() {
            // Создание объекта ошибки таким нестандартным для билера способом требуется для корректного формирования
            // блока '<Click to see difference>'
            CustomAssertionFailedError customAssertionFailedError;

            if (isNull(message)) {
                customAssertionFailedError = new CustomAssertionFailedError();
            } else {
                if (!isNull(expected) && !isNull(actual)) {
                    customAssertionFailedError = new CustomAssertionFailedError(message, expected, actual);
                } else {
                    customAssertionFailedError = new CustomAssertionFailedError(message);
                }
            }

            if (!isNull(attachment)) {
                customAssertionFailedError.setAttachment(attachment);
            }

            return customAssertionFailedError;
        }
    }
}
